import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objs as go
import plotly.io as pio
pio.templates.default = "ggplot2"
pio.renderers.default = "notebook"
# injects plotly.js into the notebook for offline plotly
# but only works for the first save, for some reason
def gsheet(spreadsheet_id, sheet_id=None, sheet_name=None):
# make sure the spreadsheet is publicly viewable
if sheet_id is not None:
return f"https://docs.google.com/spreadsheets/d/{spreadsheet_id}/gviz/tq?tqx=out:csv&gid={sheet_id}"
elif sheet_name is not None:
return f"https://docs.google.com/spreadsheets/d/{spreadsheet_id}/gviz/tq?tqx=out:csv&sheet={sheet_name}"
else:
return None
mappings = pd.read_csv(
gsheet("1IqDgYDE83fx0H1EJ9RR-6_Tda4dyDk1I69oPMPRl-6c", sheet_id=0),
dtype = str
)
difficulties = pd.read_csv(
gsheet("1IqDgYDE83fx0H1EJ9RR-6_Tda4dyDk1I69oPMPRl-6c", sheet_id=203303741)
)
available_mappings = mappings.melt(
id_vars = ['Required_Output'],
var_name = "Layout",
value_name = "Key_Code"
)
available_mappings = available_mappings.dropna().copy()
available_mappings["Key_Code"] = available_mappings["Key_Code"].str.strip().str.split(" ")
available_mappings = available_mappings.explode("Key_Code")
available_mappings["Key_Code"] = available_mappings["Key_Code"].astype(np.int16)
available_mappings = available_mappings.merge(difficulties, on="Key_Code", how="left")
available_mappings = available_mappings.drop(columns="Key_Code")
Get the total difficulty of getting an output, by pressing a key/combination of keys
summary = available_mappings.groupby(["Required_Output", "Layout"]).sum().reset_index()
summary = summary.pivot(index="Required_Output", columns=["Layout"])
summary = summary["Difficulty"].reset_index()
summary = (
mappings[["Required_Output"]]
.merge(summary, how="inner")
.set_index("Required_Output")
)
summary = summary.fillna(
summary.max().max()
)
summary.agg(["median", "mean", "std", "min", "max"]).round(2)
| Windows_ANSI_ColemakIm | Windows_ANSI_Qwerty | Windows_ISO_ColemakIm | Windows_ISO_Qwerty | |
|---|---|---|---|---|
| median | 3.85 | 6.20 | 3.85 | 6.95 |
| mean | 4.02 | 6.32 | 4.02 | 6.71 |
| std | 1.65 | 3.29 | 1.65 | 3.33 |
| min | 1.00 | 1.00 | 1.00 | 1.00 |
| max | 7.80 | 11.90 | 7.80 | 11.90 |
title = "Difficulty of Different Layouts"
fig = go.Figure().update_layout(
margin=dict(t=80, r=0, b=0, l=0),
# Title and Subtitle
title = dict(
text =
title + "<br><sup>" +
"Lower is better" + "</sup>",
x = 0,
y = 0.95
),
# axes titles
xaxis_title = "Difficulty",
yaxis_title = "",
xaxis_range = (0, 1.1*summary.max().max()),
# legend
showlegend = True,
legend = dict(
groupclick="toggleitem",
orientation = 'h',
# positioning
x = 1,
xanchor = "right",
y = 1,
yanchor = "bottom",
font = dict(
size = 10
),
itemsizing = 'constant',
# click behavior
#itemclick = 'toggleothers',
#itemdoubleclick = 'toggle'
)
)
for layout in summary.columns:
layout_split = layout.split("_")
layout_type = layout_split[1]
fig.add_trace(go.Box(
x = summary[layout],
name = f"{layout_split[0]} {layout_split[1]}<br /><b>{layout_split[2]}</b>",
legendgroup = layout_type,
legendgrouptitle_text = layout_type
))
config = dict(
doubleClickDelay = 400, # (ms) affects the single click delay; default = 300ms
displayModeBar = False,
displaylogo = False,
# scrollZoom = True,
showTips = False
)
fig.update_layout(showlegend = False).write_image(f"{title}.png")
fig.update_layout(showlegend = False).write_image(f"{title}.svg")
fig.update_layout(showlegend = True).show(config=config)